package statement;

import java.util.ArrayList;
import java.util.List;

import runtime.TypeFactory;
import util.Result;
import util.Scope;
import exception.ExpressionException;
import exception.NoMoreStepsException;
import exception.StatementExecutionException;
import exception.TypeException;
import expression.Expression;

public class IfStatement implements Statement {

	private Result result;
	private Expression expression;
	private List<Statement> trueStatements;
	private List<Statement> falseStatements;
	private int currentStep;
	private Scope scope;

	public IfStatement(Scope scope, Expression expr, List<Statement> trueSt,
			List<Statement> falseSt) {
		TypeFactory tf = TypeFactory.getInstance();
		try {
			if (!expr.getResultType().equals(tf.getType("bool"))) {
				throw new TypeException();
			}
			this.expression = expr;
			this.result = null;
			this.trueStatements = trueSt;
			this.falseStatements = falseSt;
			this.currentStep = 0;
			this.scope = scope;
		} catch (ExpressionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TypeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public IfStatement(Scope scope, Expression expr, List<Statement> trueSt) {
		this(scope, expr, trueSt, new ArrayList<Statement>());
	}

	public IfStatement(Scope scope, Expression expr) {
		this(scope, expr, new ArrayList<Statement>(), new ArrayList<Statement>());
	}

	public void addTrueStatement(Statement st) {
		this.trueStatements.add(st);
	}

	public void addFalseStatement(Statement st) {
		this.falseStatements.add(st);
	}

	@Override
	public void execute() throws StatementExecutionException,
			NoMoreStepsException {
		try {
			while (true) {
				this.nextStep();
			}
		} catch (NoMoreStepsException e) {
			// nie ma wiecej krokow
		}

	}

	@Override
	public void nextStep() throws StatementExecutionException,
			NoMoreStepsException {
		if (this.getConditionValue()) {
			if (this.currentStep >= this.trueStatements.size()) {
				throw new NoMoreStepsException();
			} else {
				this.trueStatements.get(currentStep).execute();
				this.currentStep++;
			}
		} else {
			if (this.currentStep >= this.falseStatements.size()) {
				throw new NoMoreStepsException();
			} else {
				this.falseStatements.get(currentStep).execute();
				this.currentStep++;
			}
		}

	}

	public Boolean getConditionValue() {
		if (this.result == null) {
			try {
				this.result = this.expression.evaluate();
			} catch (ExpressionException e) {
				// TODO Auto-generated catch block
				 e.printStackTrace();
			}
		}
		return (Boolean) result.getValue();
	}

	public void reset() {
		result = null;
		this.currentStep = 0;
	}
	
	public String toString() {
		return "IfStatement: [ expression: " + this.expression + ", expression result: " + this.result + ", true statements: " + this.trueStatements + ", false statements: " + this.falseStatements + ", current step: " + this.currentStep + ((this.result.getValue()!=null)?(", current statement: " + (((Boolean)(this.result.getValue()))?this.trueStatements.get(currentStep):this.falseStatements.get(currentStep))):"");
	}
}
